package org.deng.learn.distribute.lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.params.SetParams;

import java.util.Collections;
import java.util.UUID;

/**
 * @author 邓力宾
 * @date 2020/7/23 14:20
 * @desc redis 分布式锁
 */
public class RedisLock {

    private Logger logger = LoggerFactory.getLogger(RedisLock.class);
    private static final String REDIS_URL = "192.168.56.101";
    private static final int REDIS_PORT =  6379;
    private static final String LOCK_SUCCESS = "OK";
    private static final int LOCK_EXPIRE_TIME = 20; // 锁过期时间 秒
    private static final int TIME_OUT = 15 * 1000; // 获取锁超时时间
    private String lockKey = UUID.randomUUID().toString();
    //SET命令的参数
    private SetParams params = SetParams.setParams().nx().px(LOCK_EXPIRE_TIME);


    //连接池
    static  JedisPool jedisPool;
    static {
        //1 获得连接池配置对象，设置配置项
        JedisPoolConfig config = new JedisPoolConfig();
        // 1.1 最大连接数
        config.setMaxTotal(30);
        //1.2 最大空闲连接数
        config.setMaxIdle(10);
        jedisPool = new JedisPool(config,REDIS_URL,REDIS_PORT);
    }

    /**
     * 加锁
     * @param requestId
     * @return
     */
    public boolean lock(String requestId){
        Jedis jedis = jedisPool.getResource();
        long start = System.currentTimeMillis();
        try{
            while (true){
                String result = jedis.set(lockKey, requestId, params);
                if (LOCK_SUCCESS.equals(result)) {
                    return true;
                }
                long end = System.currentTimeMillis();
                if(end - start > TIME_OUT){
                    logger.warn("RedisLock get lock timout");
                    return false;
                }
                try{
                    Thread.sleep(15);
                }catch (Exception e){
                    e.printStackTrace();
                    logger.error("org.deng.learn.distribute.lock.RedisLock.lock 60=>",e);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error("org.deng.learn.distribute.lock.RedisLock.lock 65 =>", e);
        }finally {
            jedis.close();
        }

        return false;
    }

    /**
     * 解锁
     * @param requestId
     * @return
     */
    public boolean unLock(String requestId){
        Jedis jedis = jedisPool.getResource();
        String script =
                "if redis.call('get',KEYS[1]) == ARGV[1] then" +
                        "   return redis.call('del',KEYS[1]) " +
                        "else" +
                        "   return 0 " +
                        "end";
        try {
            Object result = jedis.eval(script, Collections.singletonList(lockKey),
                    Collections.singletonList(requestId));
            if("1".equals(result.toString())){
                return true;
            }
            return false;
        }finally {
            jedis.close();
        }
    }
}
